package com.universest.swordholder.model

import com.universest.swordholder.data.dao.Book
import com.universest.swordholder.data.dao.Passage
import com.universest.swordholder.data.dao.Volume
import com.universest.swordholder.data.getUserDb
import com.universest.swordholder.data.repository.BookRepository
import com.universest.swordholder.data.repository.LongTextRepository
import com.universest.swordholder.data.repository.PassageRepository
import com.universest.swordholder.data.repository.VolumeRepository
import com.universest.swordholder.task.AbstractTask
import com.universest.swordholder.task.NeedPrepareTask
import com.universest.swordholder.task.Task
import com.universest.swordholder.task.Task.TaskScope
import com.universest.swordholder.tools.UriFile
import com.universest.swordholder.tools.passageFormat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.firstOrNull

import java.io.BufferedReader
import java.io.InputStreamReader

class NovelImporter(private val file: UriFile){

    private var _completedBytes = 0L

    private var currentPassageTitle = "前言"

    private var currentContentBuilder = StringBuilder()

    private var currentVolumeTitle = ""

    private var currentVolumeId = -1

    private var volumeCount = 0;

    private var passageCount = 0;

    private val db = getUserDb()

    private val bookRepository = BookRepository(db)

    private val volumeRepository = VolumeRepository(db)

    private val passageRepository = PassageRepository(db)

    private val longTextRepository = LongTextRepository(db)

    private var bookId = -1

    private var charCount = 0;

    fun createTask(): AbstractTask<Unit, Unit>{
        return NeedPrepareTask<Unit, Unit>(
            name = "导入小说",
            prepareTask = Task<Unit, AbstractTask<Unit, Unit>>(
                name = "导入小说",
                progressMaxValue = 1000,
                initialMessage = "正在导入"
            ) {
                prepareTask(Unit)
            }
        )
    }

    suspend fun TaskScope<Unit, AbstractTask<Unit, Unit>>.prepareTask(param: Unit): AbstractTask<Unit, Unit> {
        updateMessage("正在导入中")
        val (fileName,fileSize) = file.queryFileNameAndSize()
        if(fileName.isEmpty() || fileSize == 0L){
            throw Exception("文件打开失败")
        }
        return Task<Unit, Unit>(
            name = "导入小说",
            progressMaxValue = 1000,
            initialMessage = "正在导入 $fileName"
        ) {
            importNovel(fileName, fileSize)
        }.withContext(Dispatchers.IO)
    }

    private suspend fun TaskScope<Unit, Unit>.importNovel(
        fileName: String,
        fileSize: Long
    ) {
        val novelName = fileName.substringBeforeLast(".")
        updateMessage("正在创建小说《${novelName}》")
        bookId = bookRepository.addBook(
            Book(
                bookName = novelName,
            )
        ).toInt()
        val bufferedReader = file.openFile()?.let { BufferedReader(InputStreamReader(it)) }
        if (bufferedReader == null) {
            throw Exception("文件打开失败")
        }
        bufferedReader.use {
            for (line in bufferedReader.lines()) {
                scanLine(line, fileSize)
            }
            submitCurrentPassage()
        }
    }

    private suspend fun TaskScope<Unit, Unit>.scanLine(
        line: String,
        fileSize: Long
    ) {
        checkCancelled()
        if (lineIsVolumeTitle(line)) {
            submitCurrentPassage()
            markNewVolume(line)
        } else if (lineIsPassageTitle(line)) {
            submitCurrentPassage()
            markNewPassage(line)
        } else {
            currentContentBuilder.append(line)
            currentContentBuilder.append("\n")
        }
        _completedBytes += line.toByteArray().size + 1
        updateProgress((_completedBytes * 1000 / fileSize.toDouble()).toInt(), 1000)
    }

    private suspend fun TaskScope<Unit, Unit>.markNewPassage(
        line: String
    ) {
        val title = line.trim()
        updateMessage("正在创建章：${title}")
        currentPassageTitle = title
        passageCount++
    }

    private suspend fun TaskScope<Unit, Unit>.markNewVolume(
        line: String
    ) {
        val title = line.trim()
        updateMessage("正在创建卷《${title}》")
        currentVolumeTitle = title
        currentVolumeId = volumeRepository.insert(
            Volume(
                bookId = bookId,
                name = title,
                order = volumeCount * 10
            )
        ).toInt()
        volumeCount++
    }

    private suspend fun submitCurrentPassage(){
        if(currentContentBuilder.isNotEmpty() && currentContentBuilder.indexOfFirst { !it.isWhitespace() } >= 0){
            val passageCharCount = currentContentBuilder.count { it -> !it.isWhitespace() }
            val passage = Passage(
                bookId = bookId,
                title = currentPassageTitle,
                contentId = longTextRepository.newLongText(currentContentBuilder.toString().passageFormat()).textId,
                volumeId = currentVolumeId,
                order = passageCount * 10,
                charCount = passageCharCount
            )
            charCount += passageCharCount
            passageRepository.insert(passage)
            currentContentBuilder.clear()
            bookRepository
                .getBookById(bookId)
                .firstOrNull()
                ?.copy(charCount = charCount)
                ?.let { bookRepository.updateBook(it) }
        }
    }

    private fun lineIsVolumeTitle(line: String): Boolean{
        if(line.length > 50)return false
        val pattern = Regex("""^第[一二三四五六七八九十百千万亿兆两零\d]+卷.*""")
        return pattern.matches(line.trim())
    }

    private fun lineIsPassageTitle(line: String): Boolean{
        if(line.length > 50)return false
        val trimmed = line.trim()
        if(trimmed.startsWith("间章")){
            return true
        }
        val pattern = Regex("""^第[一二三四五六七八九十百千万亿兆两零\d]+[章回篇].*""")
        return pattern.matches(trimmed) && trimmed.length < 30
    }

}